﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;


/*简单显示列表，不考虑多个元素带来的效率问题
    Scroll->Viewport->List
*/
public class ListPanel<DataType, PanelType> : MonoBehaviourUI
    where PanelType : ListPanelItem<DataType>
    where DataType : ListPanelData
{
    private int _listCount = 0;

    public ListPanelDirection Direction = ListPanelDirection.Horizontal;

    private Transform _scrollTrans;
    private ScrollRect _scrollRect;
    private RectTransform _scrollRectTrans;
    private Transform _viewPort;
    private RectTransform _viewPortRectTran;
    private Transform _contentPanel;
    private RectTransform _contentPanelTran;
    private GridLayoutGroup _layout;

    private float _cellWidth;//单元格宽
    private float _cellHeight;//单元格高
    private float _spacingX;//间隔X
    private float _spacingY;//间隔Y


    private int _visibleHorizontalNum;//能看见的水平最大CELL数，包括部分的
    private int _visibleVerticalNum;//竖直的

    private int _row;//scrollrect容纳的cell行数
    private int _col;//列数

    private int _viewPortRow;
    private int _viewPortCol;

    private GameObject _defaultItem;
    private int _firstVisibleCol = -1;//这样从-1到0也算检测到变化了
    private int _firstVisibleRow = -1;

    private bool _canUpdateView = false;//setlistdata之后才可以update
    protected virtual void Start()
    {
        _scrollTrans = transform.Find("ScrollRect");
        _scrollRectTrans = _scrollTrans.GetComponent<RectTransform>();
        _scrollRect = _scrollTrans.GetComponent<ScrollRect>();

        _viewPort = transform.Find("ScrollRect/ViewPort");

        _contentPanel = transform.Find("ScrollRect/ViewPort/ContentPanel");
        _contentPanelTran = _contentPanel.GetComponent<RectTransform>();

        _layout = _contentPanel.GetComponent<GridLayoutGroup>();

        InitDirection();

        SetViewPortAnchor();

        SetContentPanelAnchor();

        _cellWidth = _layout.cellSize.x;
        _cellHeight = _layout.cellSize.y;
        _spacingX = _layout.spacing.x;
        _spacingY = _layout.spacing.y;

        Vector2 scrollSize = _scrollRectTrans.rect.size;
        _visibleHorizontalNum = (int)(scrollSize.x / CellWidthAndSpace) + 2;
        _visibleVerticalNum = (int)(scrollSize.y / CellHeightAndSpace) + 2;

        _col =(int) ((scrollSize.x + _spacingX)/CellWidthAndSpace);
        _row = (int)((scrollSize.y + _spacingY) / CellHeightAndSpace);

        _scrollRect.onValueChanged.AddListener(OnScrollRectValueChange);

    }


    private void InitDirection()
    {
        if (Direction == ListPanelDirection.Horizontal)
        {
            _layout.startAxis = GridLayoutGroup.Axis.Vertical;
            _scrollRect.horizontal = true;
            _scrollRect.vertical = false;
        }
        else
        {
            _layout.startAxis = GridLayoutGroup.Axis.Horizontal;
            _scrollRect.horizontal = false;
            _scrollRect.vertical = true;
        }
    }

    //设置滑动对象Viewport的大小
    private void SetViewPortSize()
    {
        if (Direction == ListPanelDirection.Horizontal)
        {
            _viewPortRow = _row;
            _viewPortCol = Mathf.CeilToInt((float)_listCount / _viewPortRow);
        }
        else
        {
            _viewPortCol = _col;
            _viewPortRow = Mathf.CeilToInt((float)_listCount / _viewPortCol);

        }
        _viewPort.GetComponent<RectTransform>().sizeDelta =
                new Vector2(_viewPortCol * _cellWidth + (_viewPortCol - 1) * _spacingX,
                            _viewPortRow * _cellHeight + (_viewPortRow - 1) * _spacingY);

    }

    private void SetContentPanelSize()
    {
        if (Direction == ListPanelDirection.Horizontal)
            _contentPanel.GetComponent<RectTransform>().sizeDelta =
                new Vector2(_visibleHorizontalNum * _cellWidth + (_visibleHorizontalNum - 1) * _spacingX, 
                            _scrollRectTrans.rect.size.y);
        else
        {
            _contentPanel.GetComponent<RectTransform>().sizeDelta =
                new Vector2(_scrollRectTrans.rect.size.x,
                            _visibleVerticalNum * _cellHeight + (_visibleVerticalNum - 1) * _spacingY);
        }
    }

    private void SetViewPortAnchor()
    {
        _viewPortRectTran = _viewPort.GetComponent<RectTransform>();
        _viewPortRectTran.pivot = new Vector2(0, 1);
        _viewPortRectTran.anchorMin = new Vector2(0, 1);
        _viewPortRectTran.anchorMax = new Vector2(0, 1);
        _viewPortRectTran.anchoredPosition = new Vector2(0, 0);

    }

    private void SetContentPanelAnchor()
    {
        RectTransform contentPanelRect = _contentPanel.GetComponent<RectTransform>();
        contentPanelRect.pivot = new Vector2(0, 1);
        contentPanelRect.anchorMin = new Vector2(0, 1);
        contentPanelRect.anchorMax = new Vector2(0, 1);
        contentPanelRect.anchoredPosition = new Vector2(0, 0);
    }

    private void CreateItems()
    {
        if (_contentPanel.childCount == 0)
            Debug.LogError("no default item");
        _defaultItem = _contentPanel.GetChild(0).gameObject;
        _defaultItem.SetActive(false);

        for (int i = 0; i < VisibleNum; i++)
        {
            GameObject obj = Instantiate(_defaultItem);
            obj.SetActive(true);
            obj.transform.SetParent(_contentPanel,false);
            PanelType panel = obj.transform.GetOrAddComponent<PanelType>();
            _panels.Add(panel);
        }
    }

    private void OnScrollRectValueChange(Vector2 pos)
    {
        if(_canUpdateView)
            UpdateView();
    }

    private float CellWidthAndSpace
    {
        get { return _cellWidth + _spacingX; }
    }

    private float CellHeightAndSpace
    {
        get { return _cellHeight + _spacingY; }
    }

    private void UpdateView()
    {
        Vector2 pos = _viewPortRectTran.anchoredPosition;
        if (Direction == ListPanelDirection.Horizontal)
        {
            float x = -pos.x;
            int firstVisibleCol = (int)((x + _spacingX) / CellWidthAndSpace);
            if (_firstVisibleCol != firstVisibleCol && firstVisibleCol <_viewPortCol - _visibleHorizontalNum + 1
                && firstVisibleCol >= 0)
            {
                _firstVisibleCol = firstVisibleCol;
                _contentPanelTran.anchoredPosition =
                    new Vector2(CellWidthAndSpace * _firstVisibleCol, _contentPanelTran.anchoredPosition.y);
                UpdateItemPanels();
            }
        }
        else
        {
            float y = pos.y;
            int firstVisibleRow = (int)((y + _spacingY) / CellHeightAndSpace);
            if (_firstVisibleRow != firstVisibleRow && firstVisibleRow < _viewPortRow - _visibleVerticalNum + 1
                && firstVisibleRow >=0)
            {
                _firstVisibleRow = firstVisibleRow;
                _contentPanelTran.anchoredPosition =
                    new Vector2(_contentPanelTran.anchoredPosition.x,-CellHeightAndSpace * _firstVisibleRow);
                UpdateItemPanels();
            }
        }



    }

    //scrollrect里显示的data数目
    private int VisibleNum {
        get
        {
            if (Direction == ListPanelDirection.Horizontal)
            {
                return _row*_visibleVerticalNum;
            }
            else
            {
                return _col*_visibleHorizontalNum;
            }
        }
    }

    //更新所有的ItemPanel面板  进行数据展示
    private void UpdateItemPanels()
    {
        int startDataIndex = 0;
        if (Direction == ListPanelDirection.Horizontal)
        {
            startDataIndex = (_firstVisibleCol)*_row;
        }
        else
        {
            startDataIndex = (_firstVisibleRow)*_col;
        }

        for (int i = 0; i < VisibleNum; i++)
        {
            DataType data = _datas[startDataIndex + i];
            _panels[i].SetData(data);
        }
    }

    private List<DataType> _datas = new List<DataType>();
    private List<PanelType> _panels = new List<PanelType>(); 
    public void SetListData(List<DataType> datas)
    {
        _datas = datas;
        _listCount = datas.Count;
        SetViewPortSize();
        SetContentPanelSize();
        CreateItems();
        _canUpdateView = true;
        UpdateView();
    }

}

public enum ListPanelDirection
{
    Horizontal,
    Vertical,
}




